/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * Copyright (C) 2010 Remon van Vliet
 */
package com.google.code.mochadb.impl;

import java.util.*;

import com.google.code.mochadb.*;

/**
 * @author Remon van Vliet
 * 
 */
public class QueryImpl<D> extends OperationBuilderImpl<Query<D>, D> implements Query<D> {

	protected CompiledQuery compiledQuery;
	protected FieldFilterMode fieldFilterMode;
	protected String[] fields;
	protected SortField[] sortFields;
	protected String sort;
	protected boolean slaveOk;
	protected int limit;
	protected int skip;

	QueryImpl() {
		super();
	}

	QueryImpl(CompiledQuery compiledQuery) {
		super();

		this.compiledQuery = compiledQuery;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.Query#count()
	 */
	public long count() {
		return 0;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.Query#excludeFields(java.lang.String[])
	 */
	public Query<D> excludeFields(String... fields) {

		checkForCompiledQuery();

		if (fieldFilterMode == FieldFilterMode.INCLUDE) {
			throw new IllegalStateException("Cannot mix includeFields and excludeFields methods in a single query");
		}

		this.fieldFilterMode = FieldFilterMode.EXCLUDE;
		this.fields = fields;

		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.Query#find(java.lang.String)
	 */
	public Query<D> find(String query) {
		checkForCompiledQuery();

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.Query#getAll()
	 */
	public List<D> getAll() {
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.Query#getOne()
	 */
	public D getOne() {
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.Query#includeFields(java.lang.String[])
	 */
	public Query<D> includeFields(String... fields) {

		checkForCompiledQuery();

		if (fieldFilterMode == FieldFilterMode.EXCLUDE) {
			throw new IllegalStateException("Cannot mix includeFields and excludeFields methods in a single query");
		}

		this.fieldFilterMode = FieldFilterMode.INCLUDE;
		this.fields = fields;

		return this;

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.Query#limit(int)
	 */
	public Query<D> limit(int limit) {

		if (limit <= 0) {
			throw new IllegalArgumentException("Limit must have a non-zero positive value.");
		}

		this.limit = limit;
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.Query#skip(int)
	 */
	public Query<D> skip(int skip) {

		if (skip < 0) {
			throw new IllegalArgumentException("Skip must have a positive value.");
		}

		this.skip = skip;
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.Query#slaveOk()
	 */
	public Query<D> slaveOk() {

		this.slaveOk = slaveOk;
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.Query#sort(com.google.code.mochadb.SortField[])
	 */
	public Query<D> sort(SortField... sortFields) {
		checkForCompiledQuery();

		if (sortFields != null || sort != null) {
			throw new IllegalStateException("Can only define sorting once per query");
		}
		this.sortFields = sortFields;
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.Query#sort(java.lang.String)
	 */
	public Query<D> sort(String sort) {

		checkForCompiledQuery();

		if (sortFields != null || sort != null) {
			throw new IllegalStateException("Can only define sorting once per query");
		}
		this.sort = sort;
		return this;
	}

	private void checkForCompiledQuery() {

		if (compiledQuery != null) {
			throw new IllegalStateException("This operation is not allowed on a named query.");
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.mochadb.impl.OperationBuilderImpl#getThis()
	 */
	@Override
	protected Query<D> getThis() {
		return this;
	}

}

enum FieldFilterMode {

	INCLUDE,
	EXCLUDE
}
